package com.hzgj.bcl.soa.registry;

import com.hzgj.bcl.soa.config.ServiceDef;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import static com.hzgj.bcl.util.lang.ThreadPoolKit.getScheduledExecutorService;

/**
 * Created by warning5 on 17-6-21.
 */
class ProviderRegistryService {

    RegistryService registryService;
    private Logger logger = LoggerFactory.getLogger(getClass());
    /**
     * 是否在注册服务
     */
    private volatile AtomicBoolean refresh = new AtomicBoolean(false);

    private RegistryContext.ServerRegisterModel serverRegisterModel;

    public ProviderRegistryService(RegistryService registryService) {
        this.registryService = registryService;
    }

    public RegistryUpdater.Result upOrDownService(String service, String ipAndPort, boolean down) {
        RegistryUpdater.Result result;
        try {
            if (down) {
                result = registryService.getUpdater().downService(service, ipAndPort);
            } else {
                result = registryService.getUpdater().upService(service, ipAndPort);
            }
            if (!result.isSuccess()) {
                logger.warn(result.getInfo());
            } else {
                logger.info((down ? "down " : "up ") + service + "of " + ipAndPort + " success.");
            }
        } catch (Exception e) {
            logger.error("{}", e);
            result = new RegistryUpdater.Result(false, e.getMessage());
        }
        return result;
    }

    public RegistryUpdater.Result updateServices(List<ServiceDef.Attr> services) {
        boolean value = false;
        String message = "success";
        try {
            value = change(services);
        } catch (Exception e) {
            logger.error("{}", e);
            message = e.getMessage();
        }
        return new RegistryUpdater.Result(value, message);
    }

    private boolean change(List<ServiceDef.Attr> services) {
        updateServicesConfig(serverRegisterModel.getServices(), services);
        if (refresh.compareAndSet(false, true)) {
            registryService.getRegistry().registryService(serverRegisterModel, false);
            refresh.set(false);
        }
        return true;
    }

    public void handleRegService(final RegistryContext.ServerRegisterModel serverRegisterModel, int period, boolean pull) {

        if (!registryService.getRegistry().needLoopPullService()) {
            registryService.getRegistry().registryService(serverRegisterModel, false);
        } else {
            ScheduledExecutorService scheduledExecutorService = getScheduledExecutorService("registry-export-service-");
            this.serverRegisterModel = serverRegisterModel;
            final AtomicBoolean firstRefresh = new AtomicBoolean(true);
            scheduledExecutorService.scheduleAtFixedRate(() -> {
                if (serverRegisterModel.getServices().size() == 0) {
                    return;
                }
                final AtomicBoolean refreshTtl = new AtomicBoolean(!pull);

                if (refresh.compareAndSet(false, true)) {
                    registryService.getRegistry().registryService(serverRegisterModel, firstRefresh.get() ? false : refreshTtl.get());
                    firstRefresh.set(false);
                    refresh.set(false);
                }
            }, 0, period, TimeUnit.SECONDS);
        }
    }

    //TODO 只针对version及group
    private void updateServicesConfig(final Map<String, ServiceDef.Attr> services, List<ServiceDef.Attr> attrs) {
        if (attrs != null) {
            attrs.forEach(change_attr -> {
                ServiceDef.Attr localAttr = services.get(change_attr.getInterface());
                if (localAttr != null) {
                    logger.info("update service " + localAttr.getInterface() + " of " + localAttr.getServerDef().getHost() + ":" + localAttr.getServerDef().getPort()
                            + " group from " + localAttr.getGroup() + " to " + change_attr.getGroup());
                    localAttr.setGroup(change_attr.getGroup());

                    logger.info("update service " + localAttr.getInterface() + " of " + localAttr.getServerDef().getHost() + ":" + localAttr.getServerDef().getPort()
                            + " version from " + localAttr.getVersion() + " to " + change_attr.getVersion());
                    localAttr.setVersion(change_attr.getVersion());
                }
            });
        } else {
            logger.info("change serviceDefs is null.");
        }
    }
}
